package com.easyj.admin.sys.serviceimpl;

import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.impl.util.io.InputStreamSource;
import org.activiti.engine.impl.util.io.StringStreamSource;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentQuery;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.easyj.admin.activiti.vo.ProcessDefVO;
import com.easyj.admin.activiti.vo.ProcessReqDTO;
import com.easyj.admin.sys.service.IProcessDefService;
import com.easyj.base.common.page.Page;
import com.easyj.base.exception.ActivitiException;
import com.easyj.base.exception.EasyjException;
import com.easyj.base.exception.ValidateException;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;


/**
 *    流程管理。
 *    更新一次流程，就增加一个version。   
*/

@Service
public class ProcessDefServiceImpl implements IProcessDefService {
    @Autowired
    private RepositoryService repositoryService;


    /**
     * 显示流程
     */
    @Override
    public Page<ProcessDefVO> findProcessDefinitionList(ProcessDefVO filter) {
        List<ProcessDefVO> list = new ArrayList<ProcessDefVO>();
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
        		.orderByProcessDefinitionVersion().orderByProcessDefinitionId().desc();
        if (StringUtils.isNotBlank(filter.getName())) {
            processDefinitionQuery.processDefinitionNameLike("%" + filter.getName() + "%");
        }
        if (StringUtils.isNotBlank(filter.getKey())) {
            processDefinitionQuery.processDefinitionKeyLike("%" + filter.getKey() + "%");
        }
        
        int start=filter.getPage().getOffset().intValue();
        List<ProcessDefinition> processDefinitions = processDefinitionQuery.listPage(start, filter.getPage().getLimit());
        long count = processDefinitionQuery.count();
        if(count>0) {
        	for(ProcessDefinition p:processDefinitions) {

        		ProcessDefVO dto=new ProcessDefVO();
        		dto.setDeploymentId(p.getDeploymentId());
        		dto.setKey(p.getKey());
        		dto.setId(p.getId());
        		dto.setName(p.getName());
        		dto.setResourceName(p.getResourceName());
        		dto.setSuspended(p.isSuspended());
        		dto.setVersion(p.getVersion());
        		
        		DeploymentQuery deploymentQuery = repositoryService.createDeploymentQuery().deploymentId(p.getDeploymentId());
        		Deployment deploy=deploymentQuery.singleResult();
        		if(deploy!=null) {
        			dto.setDeploymentTime(deploy.getDeploymentTime());
        		}
        		
        		list.add(dto);
        		
        	}
        }
       
        Page<ProcessDefVO> rtn=new Page<ProcessDefVO>(list,count,filter.getPage());
		return rtn;
    }
    
    
    @Override
    public void activeProcessById(String id) {
        repositoryService.activateProcessDefinitionById(id);
    }
    
    /**
     *  /当流程被挂起时，已经发起的该流程定义的流程实例不受影响
     */
    @Override
    public void suspendProcessById(String id) {       
        
        repositoryService.suspendProcessDefinitionById(id);  
    }
    
    /**
	* 简化管理。导入流程后，直接更新部署流程
	* @param model
	* @return
	*/
	@Override
	public void impProcess(ProcessReqDTO model) throws EasyjException{
		if(StringUtils.isBlank(model.getKey())||model.getBpmnFile()==null){
			throw new ValidateException("数据不符合要求 ！");
		}
		BpmnXMLConverter converter = new BpmnXMLConverter();
		BpmnModel bpmnModel=null;
		String key=null;
        try {
			bpmnModel=converter.convertToBpmnModel(new InputStreamSource(model.getBpmnFile().getInputStream()),true,true);
			List<Process> list=bpmnModel.getProcesses();
		    if(list==null||list.size()==0) {
		    		throw new ValidateException("流程模型数据不符合要求，不能是空流程  ！"); 
		    }
		    key=list.get(0).getId();
        } catch (IOException e) {
			throw new ValidateException("上传数据错误 ！");
		}
        if(!model.getKey().equals(key)) {
        	throw new ValidateException("数据不符合要求 ！流程ID不相符。");
        }
       
        
		ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery().latestVersion();
        processDefinitionQuery.processDefinitionKey(model.getKey());
        long count = processDefinitionQuery.count();
        
        String resourseName="ImportDeploy"+System.currentTimeMillis()+".bpmn";//必须以".bpmn"结束
        if(count>0) {//update
        	repositoryService.createDeployment().name("ImportDeployUpdate")
            .addBpmnModel(resourseName, bpmnModel)
            .deploy();
        }else {
        	//创建部署            
        	repositoryService.createDeployment().name("ImportDeployAdd")
        	                .addBpmnModel(resourseName, bpmnModel)
        	                .deploy();
        }
	}
    /**
     * 简化管理。前端设计流程后，直接更新部署流程
     * @param model
     * @return
     */
    @Override
    public void updateProcess(ProcessDefVO model) throws EasyjException{
    	if(model.getId()==null||StringUtils.isBlank(model.getBpmnXml())) {
    		throw new ValidateException("流程模型数据不符合要求 ！"); 
    	}
    	// 转换成 BpmnModel 对象
        BpmnXMLConverter converter = new BpmnXMLConverter();
        BpmnModel bpmnModel=converter.convertToBpmnModel(new StringStreamSource(model.getBpmnXml()),true,true);
       
    	//原流程定义
    	ProcessDefinition process=repositoryService.getProcessDefinition(model.getId());
    	
    	//check key....
    	boolean findKey=false;
    	List<Process> list=bpmnModel.getProcesses();
    	if(list==null||list.size()==0) {
    		throw new ValidateException("流程模型数据不符合要求，不能是空流程  ！"); 
    	}
    	for(Process p:list) {
    		if(p.getId().equals(process.getKey())){
    			findKey=true;
    			break;
    		}
    	}
    	if(!findKey) {
    		throw new ValidateException("流程模型数据不符合要求，不保更改流程ID ！"); 
    	}
    	/*
    	String oldbpmnstr="";
    	try {
	    	InputStream inputStream =repositoryService.getResourceAsStream(process.getDeploymentId(),process.getResourceName());
	    	ByteArrayOutputStream result = new ByteArrayOutputStream();
	    	byte[] buffer = new byte[1024];
	    	int length;
	    	while ((length = inputStream.read(buffer)) != -1) {
	    	result.write(buffer, 0, length);
	    	}
	    	oldbpmnstr = result.toString(StandardCharsets.UTF_8.name());
    	}catch(Exception ex) {
    		throw new ActivitiException("读取流程模型错误！");
    	}
    	if(oldbpmnstr.equals(model.getBpmnXml())) {//流程没改变，直接返回
    		return;
    	}*/
    	
    	//创建部署
    	 String resourseName="DesignDeploy"+System.currentTimeMillis()+".bpmn";//必须以".bpmn"结束
    	repositoryService.createDeployment().name("DesignerDeployUpdate")
    	                .addBpmnModel(resourseName, bpmnModel)
    	                .deploy();
    	
    }
    @Override
    public void addProcess(ProcessDefVO model) throws EasyjException{
    	if(StringUtils.isBlank(model.getBpmnXml())) {
    		throw new ValidateException("流程模型数据不符合要求 ！"); 
    	}
    	// 转换成 BpmnModel 对象
        BpmnXMLConverter converter = new BpmnXMLConverter();
        BpmnModel bpmnModel=converter.convertToBpmnModel(new StringStreamSource(model.getBpmnXml()),true,true);
       
    	
    	//check key....
    	List<Process> list=bpmnModel.getProcesses();
    	if(list==null||list.size()==0) {
    		throw new ValidateException("流程模型数据不符合要求，不能是空流程  ！"); 
    	}
    	String key=list.get(0).getId();
    	ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery().latestVersion();
        processDefinitionQuery.processDefinitionKey(key);
        long count = processDefinitionQuery.count();       
        if(count>0) {
        	throw new ValidateException("已有相同流程ID的流程，不能创建相同ID的流程！"); 
        }
    	
    	
    	//创建部署
        String resourseName="DesignDeploy"+System.currentTimeMillis()+".bpmn";//必须以".bpmn"结束
    	repositoryService.createDeployment().name("DesignDeployAdd")
    	                .addBpmnModel(resourseName, bpmnModel)
    	                .deploy();
    	
    	
    }

    @Override
    public void deleteProcessByDeploymentId(String deploymentId) {
        repositoryService.deleteDeployment(deploymentId, true);
       
    }
    
    @Override
    public ProcessDefVO getModel(String processDefinitionId) throws ActivitiException {
    	ProcessDefinition p=repositoryService.getProcessDefinition(processDefinitionId);
    	String bpmnstr="";
    	try {
	    	InputStream inputStream =repositoryService.getResourceAsStream(p.getDeploymentId(),p.getResourceName());
	    	ByteArrayOutputStream result = new ByteArrayOutputStream();
	    	byte[] buffer = new byte[1024];
	    	int length;
	    	while ((length = inputStream.read(buffer)) != -1) {
	    	result.write(buffer, 0, length);
	    	}
	    	 bpmnstr = result.toString(StandardCharsets.UTF_8.name());
    	}catch(Exception ex) {
    		throw new ActivitiException("读取流程模型错误！");
    	}
    	ProcessDefVO dto=new ProcessDefVO();
		dto.setDeploymentId(p.getDeploymentId());
		dto.setKey(p.getKey());
		dto.setId(p.getId());
		dto.setName(p.getName());
		dto.setResourceName(p.getResourceName());
		dto.setBpmnXml(bpmnstr);
		dto.setVersion(p.getVersion());;
        return dto;
    }

}
